local function get_common_inst()
    local inst = require("prefabs/npc_characters/__01__crowkid_npc_common")():Common_Npc_Create()
    return inst
end

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
---- 安装容器界面
    local function container_Widget_change(theContainer)
        -----------------------------------------------------------------------------------
        ----- 容器界面名 --- 要独特一点，避免冲突
        local container_widget_name = "monster_npc_crowkid_trader_container_widget"

        -----------------------------------------------------------------------------------
        ----- 检查和注册新的容器界面
        local all_container_widgets = require("containers")
        local params = all_container_widgets.params
        if params[container_widget_name] == nil then
            params[container_widget_name] = {
                widget =
                {
                    slotpos = {},
                    animbank = "ui_woby_3x3",
                    animbuild = "ui_woby_3x3",
                    pos = Vector3(0, 330, 0),
                    side_align_tip = 160,
                },
                type = "chest",
                acceptsstacks = true,                
            }

            local yshift = (330 - 200) / 0.6
            for y = 2, 0, -1 do
                for x = 0, 2 do
                    table.insert(params[container_widget_name].widget.slotpos, Vector3(75 * x - 75 * 2 + 75, 75 * y - 75 * 2 + 75 - yshift, 0))
                end
            end
            yshift = nil
            ------------------------------------------------------------------------------------------
            ---- item test
                params[container_widget_name].itemtestfn =  function(container_com, item, slot)
                    if container_com.inst.__wanted_item == item.prefab then
                        return true
                    end            
                    return false
                end
            ------------------------------------------------------------------------------------------

            ------------------------------------------------------------------------------------------
        end
        
        theContainer:WidgetSetup(container_widget_name)
        ------------------------------------------------------------------------
        --- 开关声音
            -- if theContainer.widget then
            --     theContainer.widget.closesound = "turnoftides/common/together/water/splash/small"
            --     theContainer.widget.opensound = "turnoftides/common/together/water/splash/small"
            -- end
        ------------------------------------------------------------------------
    end

    local function add_container_before_not_ismastersim_return(inst)
        -------------------------------------------------------------------------------------------------
        ------ 添加背包container组件    --- 必须在 SetPristine 之后，
        -- local container_WidgetSetup = "wobysmall"
        if TheWorld.ismastersim then
            inst:AddComponent("container")
            inst.components.container.openlimit = 1  ---- 限制1个人打开
            -- inst.components.container:WidgetSetup(container_WidgetSetup)
            container_Widget_change(inst.components.container)

        else
            inst.OnEntityReplicated = function(inst)
                container_Widget_change(inst.replica.container)
            end
        end
        -------------------------------------------------------------------------------------------------
    end
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

local function onclose_and_trade(inst,doer)

    -- trade_data = { 
    --     wanted_image = "goldnugget",
    --     wanted_num = 10,
    --     ret_image = "log",
    --     ret_num = 99,
    --     sound_off = true
    -- }
    local cmd_table = inst.npc_everything_data:Get("trade_data")
    local COM_Container = inst.components.container
    -- inst.__wanted_item  -- prefab name
    local item_name_wanted = cmd_table.wanted_image
    local item_num_wanted = cmd_table.wanted_num
    local item_name_ret = cmd_table.ret_image
    local item_num_ret = cmd_table.ret_num


    local flag , has_num = COM_Container:Has(item_name_wanted,item_num_wanted)
    local give_back_num = 0
    if flag == true then
        local trade_times = 0
        give_back_num = has_num % item_num_wanted
        trade_times = math.floor( (has_num - give_back_num) / item_num_wanted ) 
        for i = 1, trade_times, 1 do
            doer.components.npc_base_lib:GiveItemByName(item_name_ret,item_num_ret)
        end
    else
        give_back_num = has_num
    end

    doer.components.npc_base_lib:GiveItemByName(item_name_wanted,give_back_num)
    -- for i = 1, 10, 1 do
    --     local accept_items = COM_Container.slots[i]
    --     if accept_items ~= nil and type(accept_items) == "table" and  accept_items.Remove then
    --         accept_items:Remove()
    --     end
    -- end
    local slot_clear_fn = function(item)
        -- or item.prefab == "goldnugget" or item.prefab == "npc_item_goldnugget_coin"
        if item and ( item.prefab == item_name_wanted ) then
            item:Remove()
        end
    end
    inst.components.container:ForEachItem(slot_clear_fn)
    inst.components.container:DropEverything()

end

local function fn()
    local inst = get_common_inst()

    MakeGiantCharacterPhysics(inst, 2000, .5)   --- 让NPC过重，没法被玩家推走


    -------- net_string 处理 需求物品
    inst.__wanted_item_net_string = net_string(inst.GUID, "npc_events_netvars", "crow_wanted_item")
    if not TheWorld.ismastersim then
        inst:ListenForEvent("crow_wanted_item",function()
            inst.__wanted_item = inst.__wanted_item_net_string:value()
        end)
    else
        inst:ListenForEvent("Set_Wanted_Item",function(inst,str)
            if str and type(str) == "string" then
                inst.__wanted_item = str
                inst.__wanted_item_net_string:set(str)
            end
        end)

    end


    add_container_before_not_ismastersim_return(inst)

    -- inst.entity:SetPristine()    ----- container 组件必须在 SetPristine之后
    if not TheWorld.ismastersim then --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        return inst
    end


    if inst.components.named.name == nil then
        inst.components.named.possiblenames = inst.npc_base_lib:Get_Names()
        inst.components.named:PickNewName()
    end

    inst:ListenForEvent("onclose",function(inst,_table)
        if _table == nil or _table.doer == nil then
            return
        end
        local doer  = _table.doer
        print("monster_npc_crowkid_trader  close",doer)
        onclose_and_trade(inst,doer)
    end)
    -------------------------------------------------------------------------------------------------------------
    ---- action anim event
    inst:ListenForEvent("onclose",function(inst,_table)
        -- if _table and _table.doer then
        -- end


        inst.npc_base_lib:Say("    ")
        inst.AnimState:PlayAnimation("talk_" .. tostring(math.random(2)), true)

        -- inst.AnimState:
    end)
    inst:ListenForEvent("land",function()
        inst:AddTag("INLIMBO")
        inst.DynamicShadow:Enable(false)
        local x,y,z = inst.Transform:GetWorldPosition()
        inst.Transform:SetPosition(x,20,z)
        inst.AnimState:PlayAnimation("fly_loop",true)
        inst.Physics:SetMotorVelOverride(0,-10,0)
        inst.__land_task = inst:DoPeriodicTask(0.1,function()
            local pt = Vector3( inst.Transform:GetWorldPosition() )
            if pt.y <= 0.1 then
                inst.Physics:ClearMotorVelOverride()
                inst.Physics:Stop()
                inst.Physics:Teleport(pt.x, 0, pt.z)
                inst.AnimState:PlayAnimation("land")
                inst.DynamicShadow:Enable(true)
                inst.sg:GoToState("idle")
                if inst.__land_task then
                    inst.__land_task:Cancel()
                    inst.__land_task = nil
                end
                inst:RemoveTag("INLIMBO")
            end
        end)
        local face_pt = inst.npc_base_lib:GetSpawnPoint(Vector3(x,0,z),10) or Vector3(x+3,0,z + 2)
        inst.npc_base_lib:FaceToPoint(face_pt)
    end)

    inst:ListenForEvent("flyaway",function()
        if inst:IsNearPlayer(40) == false then
            inst:Remove()
            return
        end

        inst:AddTag("INLIMBO")
        inst:DoTaskInTime(3,inst.Remove)
        inst.Physics:Stop()
        inst.DynamicShadow:Enable(false)
        inst.AnimState:PlayAnimation("takeoff_pre")
        inst.AnimState:PushAnimation("fly_loop")
        inst.Physics:SetMotorVel(math.random() * 4 - 2, math.random() * 5 + 10, math.random() * 4 - 2)

        inst:DoPeriodicTask(0.5,function()
            inst.Physics:SetMotorVel(math.random() * 4 - 2, math.random() * 5 + 10, math.random() * 4 - 2)
            -- inst.AnimState:PlayAnimation("takeoff_pre")
            inst.AnimState:PlayAnimation("fly_loop",true)
        end)

    end)
    -------------------------------------------------------------------------------------------------------------
    -- inst:ListenForEvent("tree_link",function(inst,tar_tree)
    --     inst.Ready = true
    -- end)

    inst:ListenForEvent("Set",function(inst,_table)
        if _table == nil or type(_table) ~= "table" then
            return
        end
        -- _table.pt = Vector3()
        if _table.pt and _table.pt.x then
            local pt = _table.pt
            inst.Transform:SetPosition(pt.x,pt.y,pt.z)
            inst:PushEvent("land")
        end
        inst.npc_everything_data:Set("trade_data",_table.trade_data)
        inst:PushEvent("Set_Wanted_Item",_table.trade_data.wanted_image)
    end)

    inst:DoTaskInTime(1,function()  ----------------------------------- 重加载的时候
        local cmd = inst.npc_everything_data:Get("trade_data")
        if cmd and cmd.wanted_image then
            inst:PushEvent("Set_Wanted_Item",cmd.wanted_image)
        end
    end)

    inst:DoTaskInTime(0.1,function()
        if inst.npc_everything_data:Get("trade_data") == nil or inst.Ready == nil then
            -- print("monster_npc_crowkid_trader : no data ,remove")
            inst:Remove()
        end
    end)
    -------------------------------------------------------------------------------------------------------------
    ---- 玩家靠近执行的交易。
    inst.__player_near_task = inst:DoPeriodicTask(1.5,function()
        
        local trade_data = inst.npc_everything_data:Get("trade_data") or {}
        local block_trade = trade_data.block or false
        if trade_data.block == true and inst.__player_near_task then
            -- inst.__player_near_task:Cancel()
            -- inst.__player_near_task = nil
            inst.components.container.canbeopened = false
            -- return
        end


        if inst:HasTag("INLIMBO") then
            inst.npc_everything_data:Set("Show_Trade_Bubble_Sound",0)
            return
        end

        if inst.components.container:IsOpen() then
            inst.npc_base_lib:Hide_Trade_Bubble()
            inst.npc_everything_data:Set("Show_Trade_Bubble_Sound",0)
            return
        end

        if inst:IsNearPlayer(2.5) == false then
            inst.npc_base_lib:Hide_Trade_Bubble()
            inst.npc_everything_data:Set("Show_Trade_Bubble_Sound",0)
            return
        end

        if inst.___idle_face_around_task ~= nil then
            inst.___idle_face_around_task:Cancel()
            inst.___idle_face_around_task = nil
        end

        local player = inst:GetNearestPlayer(true)
        inst.npc_base_lib:FaceToInst(player)
        if block_trade ~= true then
            trade_data.sound_off = true
            inst.npc_base_lib:Show_Trade_Bubble(trade_data)
            if inst.npc_everything_data:Add("Show_Trade_Bubble_Sound",1)%4 == 0  or  inst.npc_everything_data:Add("Show_Trade_Bubble_Sound",0) == 1 then 
                inst.npc_base_lib:Say("   ")
            end
        else
            inst.npc_base_lib:Say("   ")
        end

    end)
    -------------------------------------------------------------------------------------------------------------
    --------- 定时转向和说话
    inst:DoPeriodicTask(20,function()
        if inst:HasTag("INLIMBO") then
            return
        end

        if inst.components.container:IsOpen() then
            inst.npc_base_lib:Hide_Trade_Bubble()
            return
        end

        local x,y,z = inst.Transform:GetWorldPosition()
        if inst:IsNearPlayer(4) == true then
            inst.npc_base_lib:Hide_Trade_Bubble()
            return
        end

        if  inst.___idle_face_around_task ~= nil then
            return
        end
        inst.___idle_face_around_task = inst:DoTaskInTime(math.random(60),function()
            inst.___idle_face_around_task = nil
            local ret_pt = inst.npc_base_lib:GetSpawnPoint(inst,12) or Vector3(x,0,z+4)
            inst.npc_base_lib:FaceToPoint(ret_pt)
            inst.npc_base_lib:Say("   ")
        end)


    end)
    -------------------------------------------------------------------------------------------------------------
    --- -- 解决玩家离开当前世界后，乌鸦刷新一直不下来的问题
    inst.___land_check_task =  inst:DoPeriodicTask(10,function()
        local x,y,z = inst.Transform:GetWorldPosition()
        if y > 1 then
            inst:PushEvent("land")
        else
            if inst.___land_check_task then
                inst.___land_check_task:Cancel()
                inst.___land_check_task = nil
            end
        end
    end)

    -------------------------------------------------------------------------------------------------------------
    --- 屏蔽交易
    -------------------------------------------------------------------------------------------------------------
    return inst
end


return Prefab("monster_npc_crowkid_trader",fn)